package com.gemini.main.counter;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * com.gemini.main.counter.ReadWriteLockCounter
 *
 * @author zhanghailin
 */
public class ReadWriteLockCounter implements Counter {

    private volatile MapWithLock mapWithLock = new MapWithLock();

    /**
     * 这个方法是不会并发的,单一线程执行
     * @param saver
     */
    @Override
    public void save(Saver saver) {
        MapWithLock preMapWithLock = mapWithLock;
        mapWithLock = new MapWithLock();
        //不会一直阻塞，因为mapWithLock已被替换，新的add调用会拿到新的mapWithLock
        preMapWithLock.lock.writeLock().lock();
        preMapWithLock.map.forEach((key, value) -> {
            //value已经废弃，故无需value.like.getAndSet(0)
            saver.save(key, value.like.get(), value.comment.get());
        });
        //不能释放该锁，否则add方法中，对被替换掉的MapWithLock.lock执行tryLock会成功
        //也许，这是你第一次见到的不需要且不允许释放的锁:)
    }

    @Override
    public void add(String key, int like, int comment) {
        MapWithLock mapWithLock;
        //如果通过tryLock获取锁失败，则表示该mapWithLock已经被废弃了（因为只有废弃了的MapWithLock才会加写锁），故重新获取最新的mapWithLock
        while (!(mapWithLock = this.mapWithLock).lock.readLock().tryLock()) ;
        try {
            Adder adder = mapWithLock.map.computeIfAbsent(key, k -> new Adder());
            adder.like.getAndAdd(like);
            adder.comment.getAndAdd(comment);
        } finally {
            mapWithLock.lock.readLock().unlock();
        }
    }

    static class Adder {
        private AtomicInteger like = new AtomicInteger();
        private AtomicInteger comment = new AtomicInteger();

    }

    static class MapWithLock {
        private ConcurrentHashMap<String, Adder> map = new ConcurrentHashMap<>();
        private ReadWriteLock lock = new ReentrantReadWriteLock();
    }
}
